#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAX_CLIENTS 1024
#define BUFFER_SIZE 1024
#define PORT 8080

int set_nonblocking(int sockfd){
    int flags;
    flags = fcntl(sockfd, F_GETFL);
    if (flags == -1){
        perror("fcntl");
        return -1;
    }
    flags |= O_NONBLOCK;
    if (fcntl(sockfd, F_SETFL, flags) == -1){
        perror("fcntl");
        return -1;
    }
    return 0;
}

int main(){
    int server_fd, new_socket;
    struct sockaddr_in server_addr, client_addr;
    int server_len = sizeof(server_addr);
    int client_len = sizeof(client_addr);
    char buffer[BUFFER_SIZE] = {0};
    //用来控制监听的描述符数量
    int nfds = 1;
    //管理所有的描述符
    struct pollfd fds[MAX_CLIENTS];
    for(int i = 0; i < MAX_CLIENTS; i++){
        fds[i].fd = -1;
        fds[i].events = 0;
        fds[i].revents = 0;
    }
    //1. 创建socket
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0){
        perror("socket");
        exit(1);
    }

    //2. 设置非阻塞
    int res = set_nonblocking(server_fd);
    if(res < 0){
        perror("set_nonblocking");
        exit(1);
    }

    //将server_fd放入fds数组中，并且监听读事件
    fds[0].fd = server_fd;
    fds[0].events = POLLIN;

    //3.bind地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
   
    int bind_ret = bind(server_fd, (struct sockaddr *)&server_addr, server_len);
    if (bind_ret < 0){
        perror("bind");
        exit(1);
    }


    //4. 开始监听
    res = listen(server_fd, MAX_CLIENTS);
    if(res < 0){
        perror("listen");
        exit(1);
    }



    printf("Server is running on port [%d]...\n", PORT);
    while(1){
        //poll的参数，第一个参数是要监听的数组，第二个参数为监听的描述符数量
        //第三个参数如果没有就绪描述符，则永久等待
        int nactive = poll(fds, nfds, -1);
        if(nactive < 0){
            if(errno == EINTR)
                continue;
            perror("poll error");
            break;
        }

        //说明poll返回正常，返回的就是就绪的描述符个数
        for(int i = 0; i < nfds; i++){
            if(fds[i].fd == -1){
                continue;
            }

            //表示当前描述符有读就绪状态
            if(fds[i].revents & POLLIN){
                //1.判度大堂经理
                if(fds[i].fd == server_fd){
                    while(1){
                      new_socket =  accept(server_fd, (struct sockaddr*)&client_addr,
                        &client_len);

                     //接收连接出现错误
                      if(new_socket < 0){
                        if(errno == EAGAIN || errno == EWOULDBLOCK){
                            break;
                        }else{
                            perror("accept");
                            break;
                        }
                      }

                      //将socket设置为非阻塞
                      res = set_nonblocking(new_socket);
                      if(res < 0){
                        perror("set_nonblocking");
                        close(new_socket);
                        break;
                      }

                      //将新的连接放入fds数组中，并且监听读事件
                      int j = 0;
                      for(j = 0; j < MAX_CLIENTS; j++){
                        if(fds[j].fd == -1){
                            fds[j].fd = new_socket;
                            fds[j].events = POLLIN;
                            //更新的是监听的范围
                            if(j+1 > nfds)
                                nfds = j+1;
                            break;
                        }
                      }

                      if(j >= MAX_CLIENTS){
                        perror("too many clients");
                        close(new_socket);
                        break;
                      }

                      
                    }

                    continue;
                }
                //2.判度服务员

                int res = read(fds[i].fd, buffer, BUFFER_SIZE);
                if(res < 0){
                    //没有读出数据
                    if(errno == EAGAIN || errno == EWOULDBLOCK){
                        continue;
                    }else{
                        perror("read");
                        close(fds[i].fd);
                        fds[i].fd = -1;
                        continue;
                    }
                }

                if(res == 0){
                    printf("client [%d] closed\n", fds[i].fd);
                    close(fds[i].fd);
                    fds[i].fd = -1;
                    continue;
                }

                printf("recv from client [%d] : %s\n", fds[i].fd, buffer);

                //发送给对端
                res = write(fds[i].fd, buffer, res);
                if(res < 0){
                    perror("write");
                    close(fds[i].fd);
                    fds[i].fd = -1;
                    continue;
                }

                if(res == 0){
                    printf("client [%d] closed\n", fds[i].fd);
                    close(fds[i].fd);
                    fds[i].fd = -1;
                    continue;
                }

                continue;
            }

            //表示当前描述符有异常
            if(fds[i].revents & (POLLERR|POLLHUP|POLLNVAL)){
                printf("socket [%d] error ", fds[i].fd);   
                close(fds[i].fd);
                fds[i].fd = -1;
                continue;
            }
        }
    }

    return 0;
}